import * as THREE from "../../node_modules/three/build/three.module.js"
import {OrbitControls} from "./m__OrbitControls.js";
import { DecalGeometry } from "../../node_modules/three/examples/jsm/geometries/DecalGeometry.js";

let scene, camera, renderer, 
raycaster, mousePos = new THREE.Vector2(), 
decalMaterial, pointMaterial,
item,// item 主要物体模型
paintItems = [];// paintItems 可以被喷射的物体
const startPoint = new THREE.Object3D();
const isLaunch = false, points={active:[], inactive:[]};

init();
initRay();
animate();

export2window();

function export2window(){
    window.THREE = THREE;
    window.scene = scene;
    window.camera = camera;
    window.renderer = renderer;
    window.points = points;
}



function init(){
    (function initThree(){
        let width = innerWidth; 
        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(50, width/window.innerHeight, 0.01, 100);
        renderer = new THREE.WebGLRenderer();

        renderer.sortObjects = true;

        camera.position.z = 10;
        renderer.setSize(width, window.innerHeight);
        renderer.setClearColor(0x666666);
        document.body.appendChild(renderer.domElement);
        let control = new OrbitControls(camera, renderer.domElement);
        control.maxPolarAngle = Math.PI-0.1;
        control.minPolarAngle = 0.1;
    })();

    (function initScene(){
        //==================================camera + startPoint=========================
        startPoint.position.set(1,-2,-1);
        camera.add(startPoint);
        scene.add(camera);
 
        //=====================================room==============================
        let roomGeometry = new THREE.BoxBufferGeometry(10,10,10);
        for(let i = 0; i< roomGeometry.index.array.length; i+=3){
            let t0 = roomGeometry.index.array[i];
            roomGeometry.index.array[i] = roomGeometry.index.array[i+1];
            roomGeometry.index.array[i+1] = t0;
        }
        let room = new THREE.Mesh(
            roomGeometry,
            new THREE.MeshBasicMaterial({
                color: 0xFF0000,
                // side: THREE.BackSide,
            })
        );
        scene.add(room);
        paintItems.push(room);


        //==============================item==================================
        item = new THREE.Mesh(
            // new THREE.PlaneBufferGeometry(10,10,10),
            new THREE.BoxBufferGeometry(2,2,2),
            new THREE.MeshBasicMaterial({
                // color: 0x55aa55,
                color: 0x000000,
                // depthWrite: false
            })
        );
        scene.add(item);
        paintItems.push(item);

        //============================= light=====================================
        let light0 = new THREE.AmbientLight(0xffffff,.3);
        scene.add(light0);

        let light1 = new THREE.PointLight(0xffffff, 2, 100);
        light1.position.set(17,17,17);
        // scene.add(light1);
        // scene.add(new THREE.PointLight(0xffffff, 2, 100));
    })();

    (function initMaterial(){
        pointMaterial = new THREE.ShaderMaterial({
            uniforms: {
                color: { value: new THREE.Color( 0xffffff ) },
            },
            transparent:true,
            alphaTest:0.5,
            depthWrite: false,
            vertexShader:`
                attribute float size;
                attribute vec3 customColor;

                varying vec3 vColor;

                void main() {

                    float _size = 2.;
                    vColor = vec3(1,1,1);

                    // vColor = customColor;

                    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

                    gl_PointSize = _size * ( 300.0 / -mvPosition.z );

                    gl_Position = projectionMatrix * mvPosition;

                }
            `,
            fragmentShader:`
                uniform vec3 color;
                uniform sampler2D pointTexture;

                varying vec3 vColor;

                void main() {
                    vec2 uv = gl_PointCoord-.5;
                    float a = smoothstep(.4,.7,1.-length(uv)*1.5);

                    gl_FragColor = vec4(1.,1.,1.,a);
                    // gl_FragColor = vec4( color * vColor, 1.0 );
                    // gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );

                }
            `
        });

        const decalDiffuse =new THREE.TextureLoader().load( './decal-diffuse.png' );
        decalMaterial = new THREE.MeshPhongMaterial( {
            specular: 0x444444,
            map: decalDiffuse,
            normalScale: new THREE.Vector2( 1, 1 ),
            shininess: 30,
            transparent: true,
            depthTest: true,
            depthWrite: false,
            polygonOffset: true,
            polygonOffsetFactor: - 4,
            wireframe: false
        } );
        
    })();
}

function createPoint(intersection){
    // =============createMesh
    let positions = new Float32Array( 3 );
    positions[0]=0;
    positions[1]=0;
    positions[2]=0;
    let pointGeometry = new THREE.BufferGeometry();
    pointGeometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    let point = new THREE.Points(
        pointGeometry,
        pointMaterial
    );

    // =============set some attribute

    let traget = {};
    let offsetTraget = new THREE.Vector3();

    let goStartPoint = function(){
        startPoint.getWorldPosition(point.position);
    }

    let setTraget = function (intersection) {
        goStartPoint();
        traget.position = intersection.point;
        traget.object = intersection.object;

        let normal = intersection.face.normal.clone();
        normal.transformDirection( traget.object.matrixWorld );
        normal.multiplyScalar( 10 );
        normal.add( traget.position );


        let _tempObj = new THREE.Object3D();
        _tempObj.position.copy(traget.position);
        _tempObj.lookAt(normal);

        traget.orientation = new THREE.Euler();
        traget.orientation.copy(_tempObj.rotation);

        console.log(`orientation`,traget.orientation);



        offsetTraget.copy(traget.position);
        // offsetTraget.add( new THREE.Vector3( Math.random()*.5, Math.random()*.5, Math.random()*.5 ) );
    }

    setTraget(intersection);

    return {
        mesh: point,
        traget: traget,
        offsetTraget: offsetTraget,
        setTraget: setTraget
    };
}

function pointsFly(){
    for(let i = 0; i < points.active.length; i++){
        let speed = 0.5;
        let point = points.active[i];
        let pos = point.mesh.position;
        let traget = point.offsetTraget;

        let direction = new THREE.Vector3();
        direction.copy(traget);
        direction.sub(pos);

        if(direction.length()<=speed){ 
            // 飞到终点,结束旅程,绘制标记
            mark(point.traget.object, point.traget.position, point.traget.orientation);
            // mark(point.offsetTraget, point.traget.position, point.traget.orientation);
            // pos.set(Math.random()*.5, Math.random()*.5 ,10);
            scene.remove(point.mesh);
            points.active.splice(i,1);
            points.inactive.push(point);
        }else{
            direction.normalize().multiplyScalar(speed);
            pos.add(direction);
        }
    }
}

function pointLaunch(intersection){
    if(isLaunch){
        let point;
        if(points.inactive.length ){
            point = points.inactive.shift();
        }else{
            point = createPoint(intersection);
        }
        point.setTraget(intersection);
        points.active.push(point);
        // point.mesh.position.set(Math.random()*.5,Math.random()*.5 ,10);
        scene.add(point.mesh);
    }
}


function initRay(){
    raycaster = new THREE.Raycaster();
    var onClickPosition = new THREE.Vector2();

    renderer.domElement.addEventListener(`mousedown` , function(e){
        if(e.button != 0) return; // 如果不是左击, 直接跳出
        let rendererSize=renderer.getSize();
        
        mousePos.set(e.offsetX/rendererSize.x-.5, -(e.offsetY/rendererSize.y-.5));
        mousePos.x *= 2;
        mousePos.y *= 2;
        isLaunch = true;
    });

    renderer.domElement.addEventListener(`mousemove`,function(e){
        if(isLaunch){
            let rendererSize = renderer.getSize();
            mousePos.set(e.offsetX/rendererSize.x-.5, -(e.offsetY/rendererSize.y-.5));
            mousePos.x *= 2;
            mousePos.y *= 2;
        }
    });

    renderer.domElement.addEventListener(`mouseup` , function(e){
        isLaunch = false;
    });
}

function mark(mesh,position,orientation){
    console.log(mesh);

    
    let g = new DecalGeometry( mesh, position, orientation, new THREE.Vector3(1,1,1) );
    let markMesh = new THREE.Mesh( g , decalMaterial );
    scene.add( markMesh );
}


function animate(){
    requestAnimationFrame(animate);
    pointsFly();
    
    if(isLaunch){
        let newMousePos = new THREE.Vector2();
        newMousePos.copy(mousePos).add( new THREE.Vector2( (Math.random()*.1-.05)/(window.innerWidth/window.innerHeight), Math.random()*.1-.05) );;
        
        raycaster.setFromCamera( newMousePos, camera );
        let intersection = raycaster.intersectObjects( paintItems );

        if(intersection.length){
            // console.log(intersection.length)
            pointLaunch(intersection[0])
        }
    }


    renderer.render(scene, camera);
}